#include "querywidget.h"
#include "savedqueriesdlg.h"
#include "umsdata.h"
#include <QtGui>

#define ROLE_TYPE Qt::UserRole + 2
#define ROLE_TOP_TYPE Qt::UserRole + 3

#define TYPE_USER 1
#define TYPE_TOP  2
#define TYPE_CUBE 3
#define TYPE_BASE 4
#define TYPE_CRD  5

#define TOP_TYPE_STRUCT 1
#define TOP_TYPE_USERS  2


QueryWidget::QueryWidget()
{
	setupUi(this);
	_dbase = 0;
	connect(pbExec,SIGNAL(clicked()),SLOT(execQuery()));
	connect(pbXMLExec,SIGNAL(clicked()),SLOT(execXMLQuery()));
	cboxDBName->installEventFilter(this);		
	_structModel = 0;
	createStructModel();
	loadComboBoxValues(cboxDBName);
	splitter->setSizes(QList<int>() << 250 << 1000);
	labVectorsCount->setVisible(false);
}

void QueryWidget::showEvent(QShowEvent *)
{
	textEdit->setFocus();
}

void QueryWidget::setDatabase(UMSDatabase *dbase)
{
	_dbase = dbase;
}

void QueryWidget::execQuery()
{
	if(!_dbase) QMessageBox::warning(this,trUtf8("Ошибка"),trUtf8("Не установлено соединение с БД. Перезапустите программу."));
	//textEdit_2->setPlainText(textEdit->toPlainText());
	//qDebug() << _dbase;
	treeWidget->clear();
	QString q = textEdit->toPlainText();
	
	SavedQueriesDlg::addQuery(q);
	QTime time;
	time.start();
	if(!_dbase->exec(q)){
		labRezQuery->setText(_dbase->lastError());
	}
	else{
		labRezQuery->setText(trUtf8("Запрос выполнен удачно. Код ответа: %1. Время выполнения запроса: %2 сек.").arg(_dbase->answerCode()).arg(time.elapsed()/1000.));//.arg(QString::fromUtf8(_dbase->rawData())));
	}
	parseData();
}

void QueryWidget::parseData()
{
	//qDebug() << Q_FUNC_INFO << _dbase->rawData();
	textRezQuery->setText(QString::fromUtf8(_dbase->rawData()));
	emit queryExecuted();
	
	if(!_dbase->next()){
		tabWidget->setCurrentIndex(1);
		return;
	}
	tabWidget->setCurrentIndex(0);
	
	QStringList columns;
	columns << "uin";
	_dbase->prev();
	while(_dbase->next()){
		QStringList crds_one_vector = UMSData::coordinates(_dbase->vector());
		
		foreach(QString c,crds_one_vector){
			if(columns.indexOf(c)<0) columns << c;
		}
	}	
	_dbase->first();
	_mapNames["uin"] = trUtf8("УИН");
	//qDebug() << Q_FUNC_INFO << columns;
	treeWidget->setColumnCount(columns.count());
	QStringList columnNames;
	foreach(QString s,columns){
		if(_mapNames[s].isEmpty()) _mapNames[s]=s;
	}
	foreach(QString s,columns){
		columnNames << _mapNames[s];
	}
	QTreeWidgetItem *item = new QTreeWidgetItem(columnNames);
	for(int i=0;i<columns.size();i++){
		//qDebug() << columns.at(i);
		item->setData(i,Qt::UserRole,columns.at(i));		
	}
	treeWidget->setHeaderItem(item);
	//treeWidget->setHeaderLabels(columnNames);	
	treeWidget->setColumnWidth(0,80);
	treeWidget->clear();
	UMSData ud;
	//qDebug() << Q_FUNC_INFO << _dbase->next();
	while(_dbase->next()){
		//qDebug() << "vector out";
		ud.setVector(_dbase->vector());	
		QTreeWidgetItem *item = new QTreeWidgetItem();
		item->setText(0,ud.uin());
		treeWidget->addTopLevelItem(item);
		
		foreach(QString cn,columns){
			QStringList vlist = ud.values(cn);
			//qDebug() << cn << vlist.count();
			foreach(QString value,vlist){
			
				QTreeWidgetItem *xitem = item;
				int index = freeItemColumn(cn,xitem);			
				if(index==0) continue;
				if(xitem!=item){
					item->addChild(xitem);			
					item->setExpanded(true);
					//qDebug() << Q_FUNC_INFO << "xitem!=item";
				}
				xitem->setText(index,value);
			}
		}
	}
	labVectorsCount->setVisible(true);
	labVectorsCount->setText(trUtf8("Всего векторов: %1").arg(treeWidget->invisibleRootItem()->childCount()));	
}

int QueryWidget::freeItemColumn(const QString &name,QTreeWidgetItem *&item) //< ищет пустую колонку в item
{
	//qDebug() << Q_FUNC_INFO << name;
	
	for(int i=1;i<treeWidget->columnCount();i++){
		//if(name==treeWidget->headerItem()->text(i)) return i;
		if(name==treeWidget->headerItem()->data(i,Qt::UserRole).toString()){
			//qDebug()<< Q_FUNC_INFO << item->text(i);
			if(!item->text(i).isEmpty()){
				QTreeWidgetItem *xitem=0;
				for(int j=0;j<item->childCount();j++){
					if(item->child(j)->text(i).isEmpty()){
						xitem = item;
						break;
					}
				}
				//qDebug() << Q_FUNC_INFO << "text is null";
				if(xitem==0) xitem = new QTreeWidgetItem(item);				
				
				item = xitem;
			}
			return i;
		}
	}
	return 0;
}

void QueryWidget::setQuery(const QString &q)
{
	textEdit->setPlainText(q);
}

void QueryWidget::insertText(const QString &w)
{
	textEdit->insertPlainText(w);
	textEdit->setFocus();
}

void QueryWidget::setText(const QString &w)
{
	textEdit->setPlainText(w);
	textEdit->setFocus();
}


bool QueryWidget::eventFilter(QObject *object, QEvent *e)
{
	QComboBox *cbox = qobject_cast<QComboBox*>(object);
	bool enterPressed = e->type()==QEvent::KeyPress && (((QKeyEvent*)e)->key()==Qt::Key_Return || ((QKeyEvent*)e)->key()==Qt::Key_Enter);
	if(cbox && enterPressed){
		pbSelectDatabase->click();
	}
    return QWidget::eventFilter(object, e);
}

void QueryWidget::createStructModel()
{
	delete _structModel;
	_structModel = 0;
	_structModel = new QStandardItemModel();
	_structModel->setHorizontalHeaderItem(0,new QStandardItem(trUtf8("Структура базы данных")));
	
	
	_itemStruct = new QStandardItem(trUtf8("Схема базы данных"));
	_itemStruct->setData(TYPE_TOP,ROLE_TYPE);
	_itemStruct->setData(TOP_TYPE_STRUCT,ROLE_TOP_TYPE);
	_itemStruct->setFlags(_itemStruct->flags() & ~Qt::ItemIsEditable);
	_structModel->appendRow(_itemStruct);
	
	/*_itemUsers = new QStandardItem(trUtf8("Пользователи"));
	_itemUsers->setData(TYPE_TOP,ROLE_TYPE);
	_itemUsers->setData(TOP_TYPE_USERS,ROLE_TOP_TYPE);
	_itemUsers->setFlags(_itemStruct->flags() & ~Qt::ItemIsEditable);	
	_structModel->appendRow(_itemUsers);*/
	
	treeStruct->setModel(_structModel);
}

void QueryWidget::saveComboBoxValues(QComboBox *cbox)
{
	QStringList values;
	for(int i=0;i<cbox->count();i++){
		values << cbox->itemText(i);
	}
	QString s = cbox->currentText();
	int i = values.indexOf(s);
	if(i!=-1) values.removeAt(i);
	values.push_front(s);	
	
	QSettings sets;
	sets.beginWriteArray(cbox->objectName());
	int x=0;	
	foreach(QString s,values){
			sets.setArrayIndex(x++); 
			sets.setValue("value",s);
	}	
	sets.endArray();
}

void QueryWidget::loadComboBoxValues(QComboBox *cbox)
{
	if(!cbox) return;
	QSettings sets;
	int count = sets.beginReadArray(cbox->objectName());
	cbox->clear();
	QStringList values;
	for(int i=0;i<count;i++){
		sets.setArrayIndex(i);		
		values << sets.value("value","").toString();
	}
	cbox->addItems(values);
	cbox->setCurrentIndex(-1);
	sets.endArray();	
	cbox->setCurrentIndex(0);
}

void QueryWidget::on_pbSelectDatabase_clicked()
{
	saveComboBoxValues(cboxDBName);
	loadDatabaseStruct(cboxDBName->currentText());
	loadComboBoxValues(cboxDBName);
}

void QueryWidget::loadDatabaseStruct(const QString &dbname)
{
	//cboxDBName->setText(dbname);
	loadStruct(_dbase->databaseStruct(cboxDBName->currentText()));
}

void QueryWidget::loadStruct(const QDomDocument &doc)
{
	//qDebug() << Q_FUNC_INFO;
	QDomElement root = doc.firstChildElement("ums");
	if(root.isNull()){
		QMessageBox::warning(this,trUtf8("Ошибка"),trUtf8("Неправильная структура базы данных"));
		return;
	}
	QStandardItem *item = new QStandardItem(trUtf8("%1 (%2)").arg(root.attribute("alias")).arg(root.attribute("name")));
	item->setIcon(QIcon(":icons/images/icons/bd.png"));
	item->setData(root.attribute("name"));
	item->setData(TYPE_BASE,ROLE_TYPE);
	item->setFlags(item->flags() & ~Qt::ItemIsEditable);
	loadCubes(item,&root);
	while(_itemStruct->rowCount())	_itemStruct->removeRow(0);
	_itemStruct->appendRow(item);
	
	
	//treeStruct->resize(100,height());
	QApplication::processEvents();
	treeStruct->expandAll();
	_mapNames = mapNames(_structModel->invisibleRootItem());
}

void QueryWidget::on_treeStruct_customContextMenuRequested(QPoint pt)
{
	QModelIndex index = treeStruct->currentIndex();
	if(!index.isValid()) return;
	QStandardItem *item = _structModel->itemFromIndex(index);
	QMenu menu;	
	switch(item->data(ROLE_TYPE).toInt()){
		case TYPE_CUBE:
			connect(menu.addAction(trUtf8("Сгенерировать insert")),SIGNAL(triggered()),SLOT(generateInsert()));
			connect(menu.addAction(trUtf8("Сгенерировать select")),SIGNAL(triggered()),SLOT(generateSelect()));
			connect(menu.addAction(trUtf8("Сгенерировать delete")),SIGNAL(triggered()),SLOT(generateDelete()));
			connect(menu.addAction(trUtf8("Количество векторов")),SIGNAL(triggered()),SLOT(generateCount()));
		
			break;
		case TYPE_BASE:
			connect(menu.addAction(trUtf8("Сделать текущей")),SIGNAL(triggered()),SLOT(generateSetCurrentDatabase()));
			break;
		case TYPE_CRD:
			connect(menu.addAction(trUtf8("Выборка значений")),SIGNAL(triggered()),SLOT(generateSelectValues()));
			connect(menu.addAction(trUtf8("Количество значений")),SIGNAL(triggered()),SLOT(generateCountValues()));
			break;
			
	}
	menu.exec(((QWidget*)sender())->mapToGlobal(pt));
}

void QueryWidget::generateSetCurrentDatabase()
{
	QModelIndex index = treeStruct->currentIndex();
	if(!index.isValid()) return;
	QStandardItem *item = _structModel->itemFromIndex(index);
	QString cname = item->data().toString();
	QString query = QString("use \"%1\"").arg(cname);
	setText(query);	
	pbExec->click();
}

void QueryWidget::generateInsert()
{
	QString query = QString("insert into \"%1\" values \n%2").arg(currentCubeName()).arg(generateCrdInserts(currentItem()));
	setText(query);
	//treeStruct->selectedIndexes().at(0);
}

void QueryWidget::generateSelect()
{
	QString query = QString("select * from \"%1\"").arg(currentCubeName());
	setText(query);
}

void QueryWidget::generateDelete()
{
	QString query = QString("delete from \"%1\"").arg(currentCubeName());
	setText(query);
}

void QueryWidget::generateCount()
{
	QString query = QString("select count from \"%1\"").arg(currentCubeName());
	setText(query);
	execQuery();	
}

void QueryWidget::generateCountValues()
{
	QString query = QString("select count values from \"%1\"").arg(currentCubeName());
	setText(query);
	execQuery();	
}

QStandardItem *QueryWidget::currentItem()
{
	QModelIndex index = treeStruct->currentIndex();
	if(!index.isValid()) return 0;
	QStandardItem *item = _structModel->itemFromIndex(index);	
	return item;
}

QString QueryWidget::currentCubeName()
{
	if(currentItem()==0) return QString();
	QString cname = currentItem()->data().toString();
	return cname;
}




QString QueryWidget::generateCrdInserts(QStandardItem *pItem,int level)
{
	if(!pItem) return QString();
	QStringList values;
	
	for(int i=0;i<pItem->rowCount();i++){
		QStandardItem *item = pItem->child(i);
		QString value = QString("\"%1\"=\"\"").arg(item->data().toString());		
		for(int j=0;j<level;j++) value = "\t"+value;
		
		QString childvalues = generateCrdInserts(item,level+1);
		if(!childvalues.isEmpty()){
			QString x;
			x="{";
			for(int j=0;j<level;j++) x = "\t"+x;
			value += "\n"+x;
			value += "\n"+childvalues;
			x="}";
			for(int j=0;j<level;j++) x = "\t"+x;
			value += "\n"+x;

		}
		values << value;
	}
	return values.join(",\n");
}

QMap<QString,QString> QueryWidget::mapNames(QStandardItem *pitem)
{
	QMap<QString,QString> map;	
	if(!pitem) return map;
	for(int i=0;i<pitem->rowCount();i++){
		QStandardItem *item = pitem->child(i);
		QString alias = item->text();
		QString name = item->data().toString();		
		map[name]=alias;
		QMap<QString,QString> xmap = mapNames(item);
		foreach(QString s,xmap.keys()){
			map[s]=xmap[s];
		}
	}	
	return map;
}

void QueryWidget::on_treeStruct_activated(const QModelIndex &index)
{	
	if(!index.isValid()) return;
	QStandardItem *item = _structModel->itemFromIndex(index);
	if(!item) return;
	switch(item->data(ROLE_TYPE).toInt())
	{
/*		case TYPE_USER:
			showUserWidget(item->text());
			break;*/
		case TYPE_TOP:
			break;
		case TYPE_CUBE:
		default:
			insertText(item->data().toString());
			break;
	}

}

void QueryWidget::loadCubes(QStandardItem *pItem,QDomElement *root)
{
	QDomElement  cube = root->firstChildElement("domain");
	while(!cube.isNull()){
		QStandardItem *item = new QStandardItem(trUtf8("%1 (%2)").arg(cube.attribute("dalias")).arg(cube.attribute("name")));
		item->setIcon(QIcon(":icons/images/icons/cube.png"));
		item->setData(cube.attribute("name"));
		item->setData(TYPE_CUBE,ROLE_TYPE);
		item->setFlags(item->flags() & ~Qt::ItemIsEditable);
		pItem->appendRow(item);
		loadCoordinates(item,&cube);
		cube = cube.nextSiblingElement("domain");
	}
}

void QueryWidget::loadCoordinates(QStandardItem *pItem,QDomElement *root)
{
	QDomElement coord = root->firstChildElement("attribute");
	while(!coord.isNull()){
		QStandardItem *item = new QStandardItem(trUtf8("%1 (%2)").arg(coord.attribute("alias")).arg(coord.attribute("name")));
		item->setData(coord.attribute("name"));
		item->setData(TYPE_CRD,ROLE_TYPE);
		item->setFlags(item->flags() & ~Qt::ItemIsEditable);
		pItem->appendRow(item);
		loadCoordinates(item,&coord);		
		coord = coord.nextSiblingElement("attribute");
	}
}

void QueryWidget::generateSelectValues()
{
	QString query = QString("select values from \"%1\"").arg(currentCubeName());
	setText(query);
	pbExec->click();	
}

void QueryWidget::execXMLQuery()
{
	if(!_dbase) QMessageBox::warning(this,trUtf8("Ошибка"),trUtf8("Не установлено соединение с БД. Перезапустите программу."));
	//textEdit_2->setPlainText(textEdit->toPlainText());
	//qDebug() << _dbase;
	treeWidget->clear();
	QString q = textEdit->toPlainText();
	SavedQueriesDlg::addQuery(q);
	QTime time;
	time.start();
	if(!_dbase->execXML(q)){
		labRezQuery->setText(_dbase->lastError());
	}
	else{
		labRezQuery->setText(trUtf8("Запрос выполнен удачно. Код ответа: %1. Время выполнения запроса: %2 сек.").arg(_dbase->answerCode()).arg(time.elapsed()/1000.));//.arg(QString::fromUtf8(_dbase->rawData())));
	}
	parseData();
}
